{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "749307a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "# import openai\n",
    "\n",
    "# Instantiate the client\n",
    "client = OpenAI(\n",
    "    base_url=f\"http://192.168.202.128:3000/v1\",\n",
    "    api_key=\"sk-dlrRsAGoZm2IesTN181876Bc78Dc495dB97fB77bF62366D7\",\n",
    ")\n",
    "\n",
    "# openai.api_base = \"http://192.168.202.128:3000/v1\"\n",
    "# openai.api_key = 'sk-dlrRsAGoZm2IesTN181876Bc78Dc495dB97fB77bF62366D7'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b89722c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# The user class from the slides\n",
    "from pydantic import BaseModel\n",
    "from typing import Optional\n",
    "\n",
    "class User(BaseModel):\n",
    "    name: str\n",
    "    age: int\n",
    "    email: Optional[str] = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6af849a7",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValidationError",
     "evalue": "1 validation error for User\n  Invalid JSON: expected value at line 1 column 1 [type=json_invalid, input_value='Certainly! Below is an e...cal season, and origin.', input_type=str]\n    For further information visit https://errors.pydantic.dev/2.10/v/json_invalid",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValidationError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[42], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m completion \u001b[38;5;241m=\u001b[39m client\u001b[38;5;241m.\u001b[39mbeta\u001b[38;5;241m.\u001b[39mchat\u001b[38;5;241m.\u001b[39mcompletions\u001b[38;5;241m.\u001b[39mparse(\n\u001b[0;32m      2\u001b[0m     messages\u001b[38;5;241m=\u001b[39m[\n\u001b[0;32m      3\u001b[0m         {\n\u001b[0;32m      4\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m      5\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCan you generate an example json object describing a fruit?\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m      6\u001b[0m         }\n\u001b[0;32m      7\u001b[0m     ],\n\u001b[0;32m      8\u001b[0m     model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mqwen2.5:3b\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m      9\u001b[0m     response_format\u001b[38;5;241m=\u001b[39mUser,\n\u001b[0;32m     10\u001b[0m )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\resources\\beta\\chat\\completions.py:160\u001b[0m, in \u001b[0;36mCompletions.parse\u001b[1;34m(self, messages, model, audio, response_format, frequency_penalty, function_call, functions, logit_bias, logprobs, max_completion_tokens, max_tokens, metadata, modalities, n, parallel_tool_calls, prediction, presence_penalty, reasoning_effort, seed, service_tier, stop, store, stream_options, temperature, tool_choice, tools, top_logprobs, top_p, user, extra_headers, extra_query, extra_body, timeout)\u001b[0m\n\u001b[0;32m    153\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparser\u001b[39m(raw_completion: ChatCompletion) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ParsedChatCompletion[ResponseFormatT]:\n\u001b[0;32m    154\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m _parse_chat_completion(\n\u001b[0;32m    155\u001b[0m         response_format\u001b[38;5;241m=\u001b[39mresponse_format,\n\u001b[0;32m    156\u001b[0m         chat_completion\u001b[38;5;241m=\u001b[39mraw_completion,\n\u001b[0;32m    157\u001b[0m         input_tools\u001b[38;5;241m=\u001b[39mtools,\n\u001b[0;32m    158\u001b[0m     )\n\u001b[1;32m--> 160\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_post(\n\u001b[0;32m    161\u001b[0m     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/chat/completions\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m    162\u001b[0m     body\u001b[38;5;241m=\u001b[39mmaybe_transform(\n\u001b[0;32m    163\u001b[0m         {\n\u001b[0;32m    164\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmessages\u001b[39m\u001b[38;5;124m\"\u001b[39m: messages,\n\u001b[0;32m    165\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodel\u001b[39m\u001b[38;5;124m\"\u001b[39m: model,\n\u001b[0;32m    166\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124maudio\u001b[39m\u001b[38;5;124m\"\u001b[39m: audio,\n\u001b[0;32m    167\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfrequency_penalty\u001b[39m\u001b[38;5;124m\"\u001b[39m: frequency_penalty,\n\u001b[0;32m    168\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfunction_call\u001b[39m\u001b[38;5;124m\"\u001b[39m: function_call,\n\u001b[0;32m    169\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfunctions\u001b[39m\u001b[38;5;124m\"\u001b[39m: functions,\n\u001b[0;32m    170\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlogit_bias\u001b[39m\u001b[38;5;124m\"\u001b[39m: logit_bias,\n\u001b[0;32m    171\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlogprobs\u001b[39m\u001b[38;5;124m\"\u001b[39m: logprobs,\n\u001b[0;32m    172\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmax_completion_tokens\u001b[39m\u001b[38;5;124m\"\u001b[39m: max_completion_tokens,\n\u001b[0;32m    173\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmax_tokens\u001b[39m\u001b[38;5;124m\"\u001b[39m: max_tokens,\n\u001b[0;32m    174\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m\"\u001b[39m: metadata,\n\u001b[0;32m    175\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodalities\u001b[39m\u001b[38;5;124m\"\u001b[39m: modalities,\n\u001b[0;32m    176\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mn\u001b[39m\u001b[38;5;124m\"\u001b[39m: n,\n\u001b[0;32m    177\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparallel_tool_calls\u001b[39m\u001b[38;5;124m\"\u001b[39m: parallel_tool_calls,\n\u001b[0;32m    178\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mprediction\u001b[39m\u001b[38;5;124m\"\u001b[39m: prediction,\n\u001b[0;32m    179\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpresence_penalty\u001b[39m\u001b[38;5;124m\"\u001b[39m: presence_penalty,\n\u001b[0;32m    180\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mreasoning_effort\u001b[39m\u001b[38;5;124m\"\u001b[39m: reasoning_effort,\n\u001b[0;32m    181\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresponse_format\u001b[39m\u001b[38;5;124m\"\u001b[39m: _type_to_response_format(response_format),\n\u001b[0;32m    182\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mseed\u001b[39m\u001b[38;5;124m\"\u001b[39m: seed,\n\u001b[0;32m    183\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mservice_tier\u001b[39m\u001b[38;5;124m\"\u001b[39m: service_tier,\n\u001b[0;32m    184\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstop\u001b[39m\u001b[38;5;124m\"\u001b[39m: stop,\n\u001b[0;32m    185\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstore\u001b[39m\u001b[38;5;124m\"\u001b[39m: store,\n\u001b[0;32m    186\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstream\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[0;32m    187\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstream_options\u001b[39m\u001b[38;5;124m\"\u001b[39m: stream_options,\n\u001b[0;32m    188\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtemperature\u001b[39m\u001b[38;5;124m\"\u001b[39m: temperature,\n\u001b[0;32m    189\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtool_choice\u001b[39m\u001b[38;5;124m\"\u001b[39m: tool_choice,\n\u001b[0;32m    190\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtools\u001b[39m\u001b[38;5;124m\"\u001b[39m: tools,\n\u001b[0;32m    191\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtop_logprobs\u001b[39m\u001b[38;5;124m\"\u001b[39m: top_logprobs,\n\u001b[0;32m    192\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtop_p\u001b[39m\u001b[38;5;124m\"\u001b[39m: top_p,\n\u001b[0;32m    193\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m: user,\n\u001b[0;32m    194\u001b[0m         },\n\u001b[0;32m    195\u001b[0m         completion_create_params\u001b[38;5;241m.\u001b[39mCompletionCreateParams,\n\u001b[0;32m    196\u001b[0m     ),\n\u001b[0;32m    197\u001b[0m     options\u001b[38;5;241m=\u001b[39mmake_request_options(\n\u001b[0;32m    198\u001b[0m         extra_headers\u001b[38;5;241m=\u001b[39mextra_headers,\n\u001b[0;32m    199\u001b[0m         extra_query\u001b[38;5;241m=\u001b[39mextra_query,\n\u001b[0;32m    200\u001b[0m         extra_body\u001b[38;5;241m=\u001b[39mextra_body,\n\u001b[0;32m    201\u001b[0m         timeout\u001b[38;5;241m=\u001b[39mtimeout,\n\u001b[0;32m    202\u001b[0m         post_parser\u001b[38;5;241m=\u001b[39mparser,\n\u001b[0;32m    203\u001b[0m     ),\n\u001b[0;32m    204\u001b[0m     \u001b[38;5;66;03m# we turn the `ChatCompletion` instance into a `ParsedChatCompletion`\u001b[39;00m\n\u001b[0;32m    205\u001b[0m     \u001b[38;5;66;03m# in the `parser` function above\u001b[39;00m\n\u001b[0;32m    206\u001b[0m     cast_to\u001b[38;5;241m=\u001b[39mcast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion),\n\u001b[0;32m    207\u001b[0m     stream\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[0;32m    208\u001b[0m )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_base_client.py:1283\u001b[0m, in \u001b[0;36mSyncAPIClient.post\u001b[1;34m(self, path, cast_to, body, options, files, stream, stream_cls)\u001b[0m\n\u001b[0;32m   1269\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpost\u001b[39m(\n\u001b[0;32m   1270\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m   1271\u001b[0m     path: \u001b[38;5;28mstr\u001b[39m,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m   1278\u001b[0m     stream_cls: \u001b[38;5;28mtype\u001b[39m[_StreamT] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m   1279\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseT \u001b[38;5;241m|\u001b[39m _StreamT:\n\u001b[0;32m   1280\u001b[0m     opts \u001b[38;5;241m=\u001b[39m FinalRequestOptions\u001b[38;5;241m.\u001b[39mconstruct(\n\u001b[0;32m   1281\u001b[0m         method\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpost\u001b[39m\u001b[38;5;124m\"\u001b[39m, url\u001b[38;5;241m=\u001b[39mpath, json_data\u001b[38;5;241m=\u001b[39mbody, files\u001b[38;5;241m=\u001b[39mto_httpx_files(files), \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39moptions\n\u001b[0;32m   1282\u001b[0m     )\n\u001b[1;32m-> 1283\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m cast(ResponseT, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequest(cast_to, opts, stream\u001b[38;5;241m=\u001b[39mstream, stream_cls\u001b[38;5;241m=\u001b[39mstream_cls))\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_base_client.py:960\u001b[0m, in \u001b[0;36mSyncAPIClient.request\u001b[1;34m(self, cast_to, options, remaining_retries, stream, stream_cls)\u001b[0m\n\u001b[0;32m    957\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    958\u001b[0m     retries_taken \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m--> 960\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_request(\n\u001b[0;32m    961\u001b[0m     cast_to\u001b[38;5;241m=\u001b[39mcast_to,\n\u001b[0;32m    962\u001b[0m     options\u001b[38;5;241m=\u001b[39moptions,\n\u001b[0;32m    963\u001b[0m     stream\u001b[38;5;241m=\u001b[39mstream,\n\u001b[0;32m    964\u001b[0m     stream_cls\u001b[38;5;241m=\u001b[39mstream_cls,\n\u001b[0;32m    965\u001b[0m     retries_taken\u001b[38;5;241m=\u001b[39mretries_taken,\n\u001b[0;32m    966\u001b[0m )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_base_client.py:1066\u001b[0m, in \u001b[0;36mSyncAPIClient._request\u001b[1;34m(self, cast_to, options, retries_taken, stream, stream_cls)\u001b[0m\n\u001b[0;32m   1063\u001b[0m     log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRe-raising status error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m   1064\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_status_error_from_response(err\u001b[38;5;241m.\u001b[39mresponse) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m-> 1066\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_response(\n\u001b[0;32m   1067\u001b[0m     cast_to\u001b[38;5;241m=\u001b[39mcast_to,\n\u001b[0;32m   1068\u001b[0m     options\u001b[38;5;241m=\u001b[39moptions,\n\u001b[0;32m   1069\u001b[0m     response\u001b[38;5;241m=\u001b[39mresponse,\n\u001b[0;32m   1070\u001b[0m     stream\u001b[38;5;241m=\u001b[39mstream,\n\u001b[0;32m   1071\u001b[0m     stream_cls\u001b[38;5;241m=\u001b[39mstream_cls,\n\u001b[0;32m   1072\u001b[0m     retries_taken\u001b[38;5;241m=\u001b[39mretries_taken,\n\u001b[0;32m   1073\u001b[0m )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_base_client.py:1165\u001b[0m, in \u001b[0;36mSyncAPIClient._process_response\u001b[1;34m(self, cast_to, options, response, stream, stream_cls, retries_taken)\u001b[0m\n\u001b[0;32m   1162\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mbool\u001b[39m(response\u001b[38;5;241m.\u001b[39mrequest\u001b[38;5;241m.\u001b[39mheaders\u001b[38;5;241m.\u001b[39mget(RAW_RESPONSE_HEADER)):\n\u001b[0;32m   1163\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m cast(ResponseT, api_response)\n\u001b[1;32m-> 1165\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m api_response\u001b[38;5;241m.\u001b[39mparse()\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_response.py:319\u001b[0m, in \u001b[0;36mAPIResponse.parse\u001b[1;34m(self, to)\u001b[0m\n\u001b[0;32m    317\u001b[0m parsed \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_parse(to\u001b[38;5;241m=\u001b[39mto)\n\u001b[0;32m    318\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_given(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_options\u001b[38;5;241m.\u001b[39mpost_parser):\n\u001b[1;32m--> 319\u001b[0m     parsed \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_options\u001b[38;5;241m.\u001b[39mpost_parser(parsed)\n\u001b[0;32m    321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(parsed, BaseModel):\n\u001b[0;32m    322\u001b[0m     add_request_id(parsed, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequest_id)\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\resources\\beta\\chat\\completions.py:154\u001b[0m, in \u001b[0;36mCompletions.parse.<locals>.parser\u001b[1;34m(raw_completion)\u001b[0m\n\u001b[0;32m    153\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparser\u001b[39m(raw_completion: ChatCompletion) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ParsedChatCompletion[ResponseFormatT]:\n\u001b[1;32m--> 154\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m _parse_chat_completion(\n\u001b[0;32m    155\u001b[0m         response_format\u001b[38;5;241m=\u001b[39mresponse_format,\n\u001b[0;32m    156\u001b[0m         chat_completion\u001b[38;5;241m=\u001b[39mraw_completion,\n\u001b[0;32m    157\u001b[0m         input_tools\u001b[38;5;241m=\u001b[39mtools,\n\u001b[0;32m    158\u001b[0m     )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\lib\\_parsing\\_completions.py:110\u001b[0m, in \u001b[0;36mparse_chat_completion\u001b[1;34m(response_format, input_tools, chat_completion)\u001b[0m\n\u001b[0;32m    100\u001b[0m             \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m    101\u001b[0m                 tool_calls\u001b[38;5;241m.\u001b[39mappend(tool_call)\n\u001b[0;32m    103\u001b[0m     choices\u001b[38;5;241m.\u001b[39mappend(\n\u001b[0;32m    104\u001b[0m         construct_type_unchecked(\n\u001b[0;32m    105\u001b[0m             type_\u001b[38;5;241m=\u001b[39mcast(Any, ParsedChoice)[solve_response_format_t(response_format)],\n\u001b[0;32m    106\u001b[0m             value\u001b[38;5;241m=\u001b[39m{\n\u001b[0;32m    107\u001b[0m                 \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mchoice\u001b[38;5;241m.\u001b[39mto_dict(),\n\u001b[0;32m    108\u001b[0m                 \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmessage\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\n\u001b[0;32m    109\u001b[0m                     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mmessage\u001b[38;5;241m.\u001b[39mto_dict(),\n\u001b[1;32m--> 110\u001b[0m                     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparsed\u001b[39m\u001b[38;5;124m\"\u001b[39m: maybe_parse_content(\n\u001b[0;32m    111\u001b[0m                         response_format\u001b[38;5;241m=\u001b[39mresponse_format,\n\u001b[0;32m    112\u001b[0m                         message\u001b[38;5;241m=\u001b[39mmessage,\n\u001b[0;32m    113\u001b[0m                     ),\n\u001b[0;32m    114\u001b[0m                     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtool_calls\u001b[39m\u001b[38;5;124m\"\u001b[39m: tool_calls,\n\u001b[0;32m    115\u001b[0m                 },\n\u001b[0;32m    116\u001b[0m             },\n\u001b[0;32m    117\u001b[0m         )\n\u001b[0;32m    118\u001b[0m     )\n\u001b[0;32m    120\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m cast(\n\u001b[0;32m    121\u001b[0m     ParsedChatCompletion[ResponseFormatT],\n\u001b[0;32m    122\u001b[0m     construct_type_unchecked(\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m    128\u001b[0m     ),\n\u001b[0;32m    129\u001b[0m )\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\lib\\_parsing\\_completions.py:161\u001b[0m, in \u001b[0;36mmaybe_parse_content\u001b[1;34m(response_format, message)\u001b[0m\n\u001b[0;32m    155\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmaybe_parse_content\u001b[39m(\n\u001b[0;32m    156\u001b[0m     \u001b[38;5;241m*\u001b[39m,\n\u001b[0;32m    157\u001b[0m     response_format: \u001b[38;5;28mtype\u001b[39m[ResponseFormatT] \u001b[38;5;241m|\u001b[39m ResponseFormatParam \u001b[38;5;241m|\u001b[39m NotGiven,\n\u001b[0;32m    158\u001b[0m     message: ChatCompletionMessage \u001b[38;5;241m|\u001b[39m ParsedChatCompletionMessage[\u001b[38;5;28mobject\u001b[39m],\n\u001b[0;32m    159\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseFormatT \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m    160\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m has_rich_response_format(response_format) \u001b[38;5;129;01mand\u001b[39;00m message\u001b[38;5;241m.\u001b[39mcontent \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m message\u001b[38;5;241m.\u001b[39mrefusal:\n\u001b[1;32m--> 161\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m _parse_content(response_format, message\u001b[38;5;241m.\u001b[39mcontent)\n\u001b[0;32m    163\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\lib\\_parsing\\_completions.py:221\u001b[0m, in \u001b[0;36m_parse_content\u001b[1;34m(response_format, content)\u001b[0m\n\u001b[0;32m    219\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_parse_content\u001b[39m(response_format: \u001b[38;5;28mtype\u001b[39m[ResponseFormatT], content: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseFormatT:\n\u001b[0;32m    220\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m is_basemodel_type(response_format):\n\u001b[1;32m--> 221\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m cast(ResponseFormatT, model_parse_json(response_format, content))\n\u001b[0;32m    223\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m is_dataclass_like_type(response_format):\n\u001b[0;32m    224\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m PYDANTIC_V2:\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\openai\\_compat.py:169\u001b[0m, in \u001b[0;36mmodel_parse_json\u001b[1;34m(model, data)\u001b[0m\n\u001b[0;32m    167\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmodel_parse_json\u001b[39m(model: \u001b[38;5;28mtype\u001b[39m[_ModelT], data: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mbytes\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m _ModelT:\n\u001b[0;32m    168\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m PYDANTIC_V2:\n\u001b[1;32m--> 169\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m model\u001b[38;5;241m.\u001b[39mmodel_validate_json(data)\n\u001b[0;32m    170\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m model\u001b[38;5;241m.\u001b[39mparse_raw(data)\n",
      "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\pydantic\\main.py:656\u001b[0m, in \u001b[0;36mBaseModel.model_validate_json\u001b[1;34m(cls, json_data, strict, context)\u001b[0m\n\u001b[0;32m    654\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[0;32m    655\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m--> 656\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39m__pydantic_validator__\u001b[38;5;241m.\u001b[39mvalidate_json(json_data, strict\u001b[38;5;241m=\u001b[39mstrict, context\u001b[38;5;241m=\u001b[39mcontext)\n",
      "\u001b[1;31mValidationError\u001b[0m: 1 validation error for User\n  Invalid JSON: expected value at line 1 column 1 [type=json_invalid, input_value='Certainly! Below is an e...cal season, and origin.', input_type=str]\n    For further information visit https://errors.pydantic.dev/2.10/v/json_invalid"
     ]
    }
   ],
   "source": [
    "completion = client.beta.chat.completions.parse(\n",
    "    messages=[\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": \"Can you generate an example json object describing a fruit?\",\n",
    "        }\n",
    "    ],\n",
    "    model=\"qwen2.5:3b\",\n",
    "    response_format={},\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "9da59ee5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ParsedChatCompletion[NoneType](id='chatcmpl-35ff8d87e4f2427c8c17dfab103ace76', choices=[ParsedChoice[NoneType](finish_reason='stop', index=0, logprobs=None, message=ParsedChatCompletionMessage[NoneType](content='Certainly! Here is an example JSON object that describes a fruit:\\n\\n```json\\n{\\n  \"fruit\": {\\n    \"name\": \"Apple\",\\n    \"color\": \"Red with Green Stripes\",\\n    \"shape\": \"Round and Firm\",\\n    \"size\": \"Medium-sized\",\\n    \"texture\": \"Smooth, slightly crispy on the outside\",\\n    \"taste\": \"Sweet and Juicy\",\\n    \"season\": [\"Fall\", \"Winter\"],\\n    \"regionsOfOrigin\": {\\n      \"Mainland China\": true,\\n      \"United States\": false\\n    },\\n    \"nutritionalValue\": {\\n      \"CaloriesPer100g\": 52,\\n      \"Protein\": 0.3g,\\n      \"Fat\": 0.1g,\\n      \"Carbohydrates\": 14g,\\n      \"Fiber\": 2.1g\\n    },\\n    \"commonUses\": [\"Snacking\", \"Juicing\"]\\n  }\\n}\\n```\\n\\nThis JSON object provides a structured description of an apple, including its name, appearance, texture, taste, season availability, regions of origin, nutritional value, and typical uses.', refusal=None, role='assistant', audio=None, function_call=None, tool_calls=[], parsed=None))], created=1743993661, model='qwen2.5:3b', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=235, prompt_tokens=40, total_tokens=275, completion_tokens_details=None, prompt_tokens_details=None))\n"
     ]
    }
   ],
   "source": [
    "print(completion)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "624913c2",
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'OpenAI' object has no attribute 'Completion'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[17], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m completion \u001b[38;5;241m=\u001b[39m client\u001b[38;5;241m.\u001b[39mCompletion\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[0;32m      2\u001b[0m     model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mqwen2.5:3b\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m      3\u001b[0m     messages\u001b[38;5;241m=\u001b[39m[\n\u001b[0;32m      4\u001b[0m         {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msystem\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mYou are a helpful assistant.\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m      5\u001b[0m         {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMake up a user.\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m      6\u001b[0m     ],\n\u001b[0;32m      7\u001b[0m     response_format\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mjson_object\u001b[39m\u001b[38;5;124m\"\u001b[39m}\n\u001b[0;32m      8\u001b[0m )\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'OpenAI' object has no attribute 'Completion'"
     ]
    }
   ],
   "source": [
    "completion = client.chat.completions.parse(\n",
    "    model=\"qwen2.5:3b\",\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "        {\"role\": \"user\", \"content\": \"Make up a user.\"},\n",
    "    ],\n",
    "    response_format={\"type\": \"json_object\"}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4ccb7ce8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ParsedChatCompletionMessage[NoneType](content='Sure, I can make up a user profile for you. Here\\'s an example:\\n\\nUser Name: Alex Thompson\\n\\nAge: 32\\n\\nOccupation: Marketing Manager at a mid-sized tech company in San Francisco.\\n\\nHobbies: Playing guitar, hiking, reading self-help books.\\n\\nFavorite Food: Pizza\\n\\nMotto: \"Never let your dreams be limited by what others say can or cannot be done.\"\\n\\nInterests: Technology trends, environmental issues, fitness and wellness.\\n\\nWould you like me to add more details or change any information?', refusal=None, role='assistant', audio=None, function_call=None, tool_calls=[], parsed=None)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "completion.choices[0].message"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "8727d4d0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "user = completion.choices[0].message.parsed\n",
    "print(user)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "chat-bi",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
